package com.voice.server.channel.handle.impl;

import com.voice.core.entity.HttpHeader;
import com.voice.core.connection.Connection;
import com.voice.core.connection.ConnectionStatus;
import com.voice.core.connection.entity.Stream;
import com.voice.core.connection.entity.StreamData;
import com.voice.core.connection.impl.SocketChannelConnectionImpl;
import com.voice.server.connection.DeviceStreamConnection;
import com.voice.server.enums.DeviceStatusEnum;
import com.voice.server.message.sdk.StatusChangeMessage;
import com.voice.server.observer.impl.CmdObservable;
import com.wangjiacai.utils.ali.NettyConnection;
import com.wangjiacai.utils.ali.asr.AliAsrPool;
import com.wangjiacai.utils.ali.asr.NettySpeechTranscriberListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Optional;


@Slf4j
@Component("/device/stream/echo/success")
public class DeviceChannelStreamListener extends AbstractStreamListenerHandler<DeviceStreamConnection> {

    @Autowired
    private CmdObservable cmdObservable;
    @Autowired
    private AliAsrPool aliAsrPool;

    @Override
    public DeviceStreamConnection conversionTo(HttpHeader requestHeader, Connection connection) throws Exception {
        String deviceKey = requestHeader.get("deviceKey", String.class);
        String userId=requestHeader.get("userId",String.class);
        DeviceStreamConnection deviceConnection=new DeviceStreamConnection((SocketChannelConnectionImpl) connection,userId, deviceKey);
        getNettyConnection(deviceConnection);
        return deviceConnection;
    }

    @Override
    public void onStreamRead(DeviceStreamConnection connection, byte[] bytes) {
        getNettyConnection(connection).ifPresent(nettyConnection -> {
            try {
                nettyConnection.sendBinary(bytes);
            }catch (Exception e){
                onStreamRead(connection,bytes);
            }
        });
    }

    @Override
    public void onDataRead(DeviceStreamConnection connection, Stream stream, StreamData streamData) {}

    @Override
    public void onStatusChange(ConnectionStatus status, DeviceStreamConnection connection) {
        switch (status) {
            case CLOSED:
                log.info("DeviceStreamConnection:{} 断开",connection);
                if(connection.getNettyConnection()!=null) connection.getNettyConnection().close();
                cmdObservable.notifyObservers(connection.getUserId(),connection.getDeviceKey(),new StatusChangeMessage(connection.getUserId(),connection.getDeviceKey(), DeviceStatusEnum.Offline.getCode()));
                break;
            case AUTHORIZED:
                log.info("DeviceStreamConnection:{} 连接",connection);
                cmdObservable.notifyObservers(connection.getUserId(),connection.getDeviceKey(),new StatusChangeMessage(connection.getUserId(),connection.getDeviceKey(), DeviceStatusEnum.Online.getCode()));
                break;
        }
    }

    private Optional<NettyConnection> getNettyConnection(DeviceStreamConnection deviceConnection) {
        if(deviceConnection.getNettyConnection()==null||!deviceConnection.getNettyConnection().isActive()){
            try {
                NettyConnection nettyConnection = aliAsrPool.getConnection(new NettySpeechTranscriberListener(){
                    @Override
                    public void onMessage(String message) {
                        if(!StringUtils.isEmpty(message)){
                            System.out.println(message);
                            cmdObservable.notifyObservers(deviceConnection.getUserId(),deviceConnection.getDeviceKey(),message);
                        }
                    }
                });
                deviceConnection.setNettyConnection(nettyConnection);
                return Optional.of(nettyConnection);
            } catch (Exception e) {
                return Optional.empty();
            }
        }
        return Optional.of(deviceConnection.getNettyConnection());
    }

}
